#include "Common.h"

TimedEvent::TimedEvent(Callback* cb, ui32 interval, ui32 count, ui32 type) : m_cb(cb), m_time(interval), m_ref(count),
m_inref(count), m_lastup(0), type(type)
{
}

bool TimedEvent::DecRef()
{
	if(m_ref)
		--m_ref;
	if(!m_ref && m_inref)
		return false;
	if(!m_inref)
		return true;
	return true;
}

bool EventHolder::Update(ui32 time)
{
	if(!this || m_events.size() == 0)
		return false;
	m_evmutex.Acquire();
	std::set<TimedEvent*>::iterator itr = m_events.begin();
	std::set<TimedEvent*>::iterator end = m_events.end();
	std::set<TimedEvent*> toremove;

	if(!(&itr) || !(&end))
		return false;

	for( ; itr != end && m_events.size(); ++itr)
	{
		if(!(*itr))
		{
			toremove.insert(*itr);
			end = m_events.end();
			if(itr == end)
				break;
		}
		(*itr)->m_lastup += time;
		if((i32)(*itr)->m_lastup - (i32)(*itr)->m_time >= 0)
		{
			(*itr)->m_lastup -= (*itr)->m_time;
			if((*itr)->m_cb)
				(*itr)->m_cb->Execute();
			if(!(*itr)->DecRef())
			{
				toremove.insert(*itr);
				end = m_events.end();
				if(itr == end)
					break;
			}
		}
	}
	itr = toremove.begin();
	end = toremove.end();
	for( ; itr != end; ++itr)
	{
		m_events.erase(*itr);
		delete (*itr);
	}
	toremove.clear();
	m_evmutex.Release();
	return (m_events.size() > 0);
}

void EventHolder::Unload()
{
	if(m_worker)
		m_worker->RemoveHolder(this);
}

void EventHolder::ForceRegister(EventWorker* registerer)
{
	if(m_worker)
		m_worker->RemoveHolder(this);
	m_worker = registerer;
	m_worker->AddHolder(this);
}

void EventHolder::RemoveEvents()
{
	m_evmutex.Acquire();
	m_events.clear();
	m_evmutex.Release();
}

void EventHolder::RemoveEvent(TimedEvent* te)
{
	m_evmutex.Acquire();
	std::set<TimedEvent*>::iterator itr = m_events.find(te);
	if(itr != m_events.end())
		m_events.erase(itr);
	m_evmutex.Release();
}

void EventHolder::RemoveEventsByType(ui32 type)
{
	m_evmutex.Acquire();
	if(!m_events.size())
	{
		m_evmutex.Release();
		return;
	}
	std::set<TimedEvent*>::iterator itr = m_events.begin();
	for( ; itr != m_events.end() && m_events.size(); ++itr)
	{
		if(!(*itr))
			continue;
		if((*itr)->type == type)
		{
			m_events.erase(itr);
			if(itr == m_events.end())
				break;
		}
	}
	m_evmutex.Release();
}